﻿using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using FluidKit.Controls;
using FluidKit.Samples;
using System.IO;
using System.Linq;
using KinectControl;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Navigation;


namespace VitrineInterativa
{
    /// <summary>
    /// 	Interaction logic for Window1.xaml
    /// </summary>
    [ExportExample("ElementFlow")]
    public partial class ElementDisplay
    {
        //Core Kinect
        private KinectController kinect;

        //StoryBoard VideoFull
        private Storyboard sbVideoFull;

        Image img = new Image();
        
        private StringCollection _dataSource;

        private LayoutBase[] _layouts = {
		                                	new Wall(),
		                                	new SlideDeck(),
		                                	new CoverFlow(),
		                                	new Carousel(),
		                                	new TimeMachine2(),
		                                	new ThreeLane(),
		                                	new VForm(),
		                                	new TimeMachine(),
		                                	new RollerCoaster(),
		                                	new Rolodex(),
		                                };

        private Random _randomizer = new Random();

        private int _viewIndex;

        string pastaRaiz = Config.PastaRaiz;

        System.Collections.Specialized.NameValueCollection appSettings = ConfigurationManager.AppSettings;

        bool pausado = false;
        bool tutorialAtivo = false;


        public ElementDisplay()
        {
            InitializeComponent();                       

            Loaded += Window1_Loaded;

            this.GridPrincipal.Unloaded += new RoutedEventHandler(GridPrincipal_Unloaded);            
        }

        void GridPrincipal_Unloaded(object sender, RoutedEventArgs e)
        {
            if(this.kinect != null)
                this.kinect.Dispose();            
        }

        private void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            iniciaKinect();

            //Carrega Storyboard
            this.sbVideoFull = (Storyboard)this.Resources["sbVideoFull"];
            if(this.sbVideoFull != null)
                this.sbVideoFull.Completed += new EventHandler(sbVideoFull_Completed);

            BrushConverter conv = SetBackgroundColor();
                                   
            txbNomeAlbum.Foreground = conv.ConvertFromString(Config.CorTituloAlbum) as SolidColorBrush;
            
            _elementFlow.Layout = _layouts[3]; //seta carousel
            _elementFlow.SelectedIndex = 0; //define primeiro elemento
            _dataSource = FindResource("DataSource") as StringCollection;
            _elementFlow.Focus(); //seta foco inicial no element flow

            //gera imagem dos slides do powerpoint
            PowerPointToPNG();

            //Cria a capa(bolinho de foto empilhado) de cada album
            CapaAlbum objCapa = new CapaAlbum();
            
            //Brush transparente
            objCapa.CriarCapa(Brushes.Transparent);

            carregaCapaAlbum(); //retorna capa.png de cada album
            configuraCarousel(); //configura as propriedades do carousel
            carregaNomeAlbum();

            this.WindowState = System.Windows.WindowState.Maximized;

            AdicionaMediaIcon("pack://application:,,,/image/presentation.png");
        }
        
        private BrushConverter SetBackgroundColor()
        {
            //configura cor do fundo e do nome do album
            BrushConverter conv = new BrushConverter();
            if (!Config.CorDoFundo.Contains("\\"))
            {
                Brush corFundo = conv.ConvertFromString(Config.CorDoFundo) as SolidColorBrush;
                //FUndo da tela principal
                this.Background = corFundo;
            }
            else
            {
                try
                {
                    this.Background = new ImageBrush(new BitmapImage(new Uri(Environment.CurrentDirectory + Config.CorDoFundo, UriKind.RelativeOrAbsolute))); //BaseUriHelper.GetBaseUri(this), Config.CorDoFundo)));
                }
                catch
                {
                    Brush corFundo = conv.ConvertFromString("Black") as SolidColorBrush;
                    this.Background = corFundo;
                }
            }
            return conv;
        }
        
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                DoKeyDown(e.Key);
            }
            catch (Exception ex)
            {
                Log.GravarLog("Erro no evento KeyDown: ", ex);
            }

        }

        private void DoKeyDown(Key key)
        {
            if (!pausado)
            {
                switch (key)
                {
                    case Key.NumPad6:
                        if (_elementFlow.SelectedIndex == _elementFlow.ContainerCount - 1)
                            _elementFlow.SelectedIndex = 0;
                        else
                            _elementFlow.SelectedIndex += 1;

                        ConfiguraZoom();
                        carregaNomeAlbum();
                        break;
                    case Key.NumPad4:
                        if (_elementFlow.SelectedIndex == 0)
                            _elementFlow.SelectedIndex = _elementFlow.ContainerCount - 1;
                        else
                            _elementFlow.SelectedIndex -= 1;

                        ConfiguraZoom();
                        carregaNomeAlbum();
                        break;
                    //enter
                    case Key.Return:
                        EntrarAlbum();
                        break;
                    //backspace
                    case Key.Back:
                        SairAlbum();
                        break;
                    //zoom
                    case Key.NumPad1:
                        if (!GridPrincipal.Children.Contains(img))
                            AplicaZoom();
                        else
                            RetirarZoom();
                        break;
                    //F12 para alterar o modo de visualização do elementflow
                    case Key.F12:
                        ChangeVisualizationMode();
                        break;
                }
            }

            if (key.Equals(Key.NumPad8))
            {
                Pause();
            }
        }

        private void SairAlbum()
        {
            //só funciona quando é coverflow
            if (_elementFlow.Layout == _layouts[2])
            {
                configuraCarousel();
                carregaCapaAlbum();
                carregaNomeAlbum();
                RetirarZoom();
                //Carrega tutorial
                this.ucTutorial.PathVideo = "Image/tutorial_carousel.avi";
            }
        }

        private void EntrarAlbum()
        {
            //só funciona quando é carousel
            if (_elementFlow.Layout == _layouts[3])
            {
                configuraCoverFlow();
                carregaImagensAlbum();
                RetirarZoom();
                AplicaZoom();
                this.ucTutorial.PathVideo = "Image/tutorial_coverflow.avi";
            }
        }

        private void Pause()
        {
            if (pausado)
            {
                pausado = false;
                AdicionaMediaIcon("pack://application:,,,/image/presentation.png");
                this.BorderBrush = null;
            }
            else
            {
                pausado = true;
                AdicionaMediaIcon("pack://application:,,,/image/pause.png");
                this.BorderBrush = Brushes.Red;
                this.BorderThickness = new Thickness(3, 3, 3, 3);
            }
        }

        private void AdicionaMediaIcon(string path)
        {
            BitmapImage src = LoadBitmap(path);
            imgMedia.Source = src;
        }

        private static BitmapImage LoadBitmap(string path)
        {
            BitmapImage src = new BitmapImage();
            src.BeginInit();
            src.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
            src.CacheOption = BitmapCacheOption.OnLoad;
            src.EndInit();
            return src;
        }

        private void PowerPointToPNG()
        {
            try
            {
                FileInfo[] AllPPT = Uteis.ListaPowerPointFile();

                if (AllPPT != null && AllPPT.Count() > 0)
                {
                    if (!Directory.Exists(AllPPT[0].DirectoryName + "\\PowerPoint_Processado"))
                        Directory.CreateDirectory(AllPPT[0].DirectoryName + "\\PowerPoint_Processado");
                }

                foreach (var ppt in AllPPT)
                    Uteis.exportaPPTtoPNG(ppt.FullName, Config.PastaRaiz + ppt.Name.Substring(0, ppt.Name.LastIndexOf('.')), ppt.DirectoryName + "\\PowerPoint_Processado\\" + ppt.Name);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Houve um erro ao ler arquivo do powerpoint: " + ex.Message);
            }
        }

        #region Zoom
        private void ConfiguraZoom()
        {
            BitmapImage src = LoadBitmap(_dataSource[_elementFlow.SelectedIndex].ToString());
            img.Source = src;
            img.Stretch = Stretch.Uniform;
        }

        private void RetirarZoom()
        {
            if (GridPrincipal.Children.Contains(img))
            {
                GridPrincipal.Children.Remove(img);

                Grid.SetRow(_elementFlow, 3);
                Grid.SetRowSpan(_elementFlow, 7);
                Grid.SetColumn(_elementFlow, 0);
                Grid.SetColumnSpan(_elementFlow, 4);
            }
        }

        private void AplicaZoom()
        {
            if (!GridPrincipal.Children.Contains(img))
            {
                FadeIn();
                ConfiguraZoom();

                GridPrincipal.Children.Add(img);

                
                Grid.SetRow(img, 3);
                Grid.SetRowSpan(img, 7);
                Grid.SetColumn(img, 0);
                Grid.SetColumnSpan(img, 4);
            }
        }
        #endregion

        #region FadeIn/FadeOut
        private void FadeIn()
        {
            DoubleAnimation fadeInAnimation = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(1)));
            Storyboard.SetTarget(fadeInAnimation, img);
            Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(UIElement.OpacityProperty));
            Storyboard sb = new Storyboard();
            sb.Children.Add(fadeInAnimation);
            sb.Begin();
        }

        private void FadeOut()
        {
            DoubleAnimation fadeInAnimation = new DoubleAnimation(1, 0, new Duration(TimeSpan.FromSeconds(1)));
            Storyboard.SetTarget(fadeInAnimation, img);
            Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(UIElement.OpacityProperty));
            Storyboard sb = new Storyboard();
            sb.Children.Add(fadeInAnimation);
            sb.Begin();
        }
        #endregion


        private void ChangeVisualizationMode()
        {
            _viewIndex = (_viewIndex + 1) % _layouts.Length;
            _elementFlow.Layout = _layouts[_viewIndex];         
        }

        private void ChangeSelectedIndex(object sender, RoutedPropertyChangedEventArgs<double> args)
        {
            _elementFlow.SelectedIndex = (int)args.NewValue;
        }

        private void carregaCapaAlbum()
        {
            string path = pastaRaiz;

            DirectoryInfo objDir = new DirectoryInfo(path);
            var lstDirAlbum = objDir.GetDirectories().Where(t => !t.Name.Equals("PowerPoint_Processado"));

            _dataSource.Clear();
            //varre cada album para encontrar a capa
            foreach (var album in lstDirAlbum)
            {
                //seleciona as capas de cada album
                var files = new DirectoryInfo(string.Format(path + @"{0}\", album.Name))
                    .GetFileSystemInfos()
                    .Where(t => t.Name.Contains("capa.png"))
                    .ToList();

                for (int i = 0; i < files.Count; i++)
                    _dataSource.Insert(i, files[i].FullName);
            }

            _elementFlow.SelectedIndex = 0;
        }

        private void carregaImagensAlbum()
        {
            string path = _elementFlow.SelectedValue.ToString().Replace("capa.png", string.Empty);

            _dataSource.Clear();

            FileInfo[] imagens = Uteis.ListaFotosDoAlbum(path, string.Empty);

            //varre cada album para encontrar a capa
            for (int i = 0; i < imagens.Count(); i++)
                _dataSource.Insert(i, imagens[i].FullName);


            _elementFlow.Camera.FieldOfView = Convert.ToDouble(appSettings["CoverflowFieldOfView"]);

            _elementFlow.SelectedIndex = 0;
        }

        private void carregaNomeAlbum()
        {
            //só carrega o nome do album quando é carousel
            if (_elementFlow.Layout == _layouts[3] && _elementFlow.SelectedValue != null)
            {
                txbNomeAlbum.Text = _elementFlow.SelectedValue.ToString()
                    .Replace("capa.png", string.Empty)
                    .Replace(pastaRaiz, string.Empty)
                    .Replace(@"\", string.Empty);
            }
        }

        private void configuraCarousel()
        {
            //seta carousel
            _elementFlow.Layout = _layouts[3];

            ////configura propriedades
            _elementFlow.TiltAngle = Convert.ToDouble(appSettings["CarouselTiltAngle"]);
            _elementFlow.ItemGap = Convert.ToDouble(appSettings["CarouselItemGap"]); //espaço entre as fotos
            _elementFlow.FrontItemGap = Convert.ToDouble(appSettings["CarouselFrontItemGap"]);
            _elementFlow.PopoutDistance = Convert.ToDouble(appSettings["CarouselPopoutDistance"]);

            _elementFlow.Camera.FieldOfView = Convert.ToDouble(appSettings["CarouselFieldOfView"]);

        }

        private void configuraCoverFlow()
        {
            //seta coverflow
            _elementFlow.Layout = _layouts[2];

            //configura propriedades
            _elementFlow.TiltAngle = Convert.ToDouble(appSettings["CoverflowTiltAngle"]);
            _elementFlow.ItemGap = Convert.ToDouble(appSettings["CoverflowItemGap"]);
            _elementFlow.FrontItemGap = Convert.ToDouble(appSettings["CoverflowFrontItemGap"]);
            _elementFlow.PopoutDistance = Convert.ToDouble(appSettings["CoverflowPopoutDistance"]);

            _elementFlow.Camera.FieldOfView = Convert.ToDouble(appSettings["CoverflowFieldOfView"]);
        }


        #region Kinect

        private void iniciaKinect()
        {
            try
            {
                this.kinect = new KinectController();
                //Evento de Video
                this.kinect.videoFrameKinect += new KinectController.VideoFrameHandler(kinect_videoFrameKinect);

                //Evento posição gestos
                this.kinect.posicoesMembros += new KinectController.PosicoesHandler(kinect_posicoesMembros);

                //Eventos de gestos
                //this.kinect.ExtendeMaoDireita += new KinectController.maoDireitaExtendida(kinect_ExtendeMaoDireita);
                //this.kinect.ExtendeMaoEsquerda += new KinectController.maoEsquerdaExtendida(kinect_ExtendeMaoEsquerda);
                //this.kinect.FrenteMaoDireita += new KinectController.maoDireitaFrente(kinect_FrenteMaoDireita);
                //this.kinect.FrenteMaoEsquerda += new KinectController.maoEsquerdaFrente(kinect_FrenteMaoEsquerda);
                this.kinect.MaosFrente += new EventHandler(kinect_MaosFrente);

                //Novos gestos swipe
                //this.kinect.MakeCirculo += new EventHandler(kinect_MakeCirculo);
                this.kinect.SwipeDireita += new EventHandler(kinect_SwipeDireita);
                this.kinect.SwipeEsquerda += new EventHandler(kinect_SwipeEsquerda);
                this.kinect.DuasMaosExtendidas += new EventHandler(kinect_DuasMaosExtendidas);

                //Evento Tutorial
                //this.kinect.ChamaTutorial += new KinectController.callTutorial(kinect_ChamaTutorial);

                //Evento para Testes
                //this.kinect.GetCoordenadas += new EventHandler<MyEventArgs>(kinect_GetCoordenadas);

                //Eventos de controle - Video FullScreen
                this.kinect.AtivaVideoFull += new EventHandler(kinect_AtivaVideoFull);
                this.kinect.DesativaVideoFull += new EventHandler(kinect_DesativaVideoFull);

                //habilita/desabilita comandos de voz e pause
                if (!Config.ModoApresentacao.ToUpper().Equals("VITRINE"))
                {
                    this.kinect.MaoAcimaCabeca += new KinectController.maoDireitaOrelha(kinect_MaoAcimaCabeca);

                    this.kinect.AudioNext += new EventHandler(kinect_AudioNext);
                    this.kinect.AudioBack += new EventHandler(kinect_AudioBack);
                    this.kinect.AudioReturn += new EventHandler(kinect_AudioReturn);
                    this.kinect.AudioEnter += new EventHandler(kinect_AudioEnter);
                    this.kinect.AudioPause += new EventHandler(kinect_AudioPause);
                    this.kinect.AudioZoom += new EventHandler(kinect_AudioZoom);

                    kinect.InitializeSpeechRecognition();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Log.GravarLog("Kinect não encontrado", ex);
            }
        }
        
        /// <summary>
        /// Evento para Desativar o Video FullScreen
        /// </summary>
        void kinect_DesativaVideoFull(object sender, EventArgs e)
        {
            //Grid.Row="4" Grid.RowSpan="2" Grid.Column="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" VerticalAlignment="Center" Panel.ZIndex="1" >
            if (this.sbVideoFull != null)
            {
                this.sbVideoFull.Begin();                
            }                                              
        }


        void sbVideoFull_Completed(object sender, EventArgs e)
        {
            //Ao finalizar a animação
            this.vbCamera.SetValue(Grid.ColumnProperty, 2);
            this.vbCamera.SetValue(Grid.RowProperty, 4);
            this.vbCamera.SetValue(Grid.ColumnSpanProperty, 2);
            this.vbCamera.SetValue(Grid.RowSpanProperty, 2);
            this.vbCamera.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Right);
            this.vbCamera.SetValue(VerticalAlignmentProperty, VerticalAlignment.Center);
            
            //Para a animação
            this.sbVideoFull.Stop();

            this.vbTutorial.Visibility = System.Windows.Visibility.Visible;
        }

        /// <summary>
        /// Evento para Ativar o Video FullScreen
        /// </summary>
        void kinect_AtivaVideoFull(object sender, EventArgs e)
        {
            //Grid.Row="3" Grid.RowSpan="6" Grid.Column="0" Grid.ColumnSpan="4"

            this.vbCamera.SetValue(Grid.ColumnProperty, 0);
            this.vbCamera.SetValue(Grid.RowProperty, 3);
            this.vbCamera.SetValue(Grid.ColumnSpanProperty, 4);
            this.vbCamera.SetValue(Grid.RowSpanProperty, 6);
            this.vbCamera.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
            this.vbCamera.SetValue(VerticalAlignmentProperty, VerticalAlignment.Center);

            this.vbTutorial.Visibility = System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// Método para implementação de lógica
        /// quando o tutorial for chamado
        /// </summary>
        void kinect_ChamaTutorial()
        {
            Tutorial tutorial = new Tutorial();            
            tutorial.FinalizaTutorial += (sender, e) =>
                {
                    this.GridMain.Children.Remove(tutorial);
                    this.kinectCamera.Visibility = System.Windows.Visibility.Visible;                    
                    this.tutorialAtivo = false;
                };
                        
            this.GridMain.Children.Add(tutorial);
            this.kinectCamera.Visibility = System.Windows.Visibility.Hidden;            
            this.tutorialAtivo = true;
            this.SairAlbum();
        }
                
        void kinect_MaoAcimaCabeca()
        {
            this.DoKeyDown(Key.NumPad8);
        }

        //void kinect_GetCoordenadas(object sender, MyEventArgs e)
        //{
        //    if (e.parameter != null)
        //    {
        //        List<CoordenadasModel> listaCoordenadas = (List<CoordenadasModel>)e.parameter;

        //        foreach (var item in listaCoordenadas)
        //        {
        //            string text = string.Format("\n {0} - X: {1}, Y: {2}, Z: {3}", item.Membro, item.Joint.Position.X, item.Joint.Position.Y, item.Joint.Position.Z);
        //            System.IO.File.AppendAllText(@"C:\Temp\log.txt", text);

        //        }
        //    }
        //}

        void kinect_DuasMaosExtendidas(object sender, EventArgs e)
        {
            this.DoKeyDown(Key.NumPad1);
        }

        void kinect_MaosFrente(object sender, EventArgs e)
        {            
            //if (!this.tutorialAtivo)            
                if (_layouts[3] == _elementFlow.Layout) //Se está no carrosel.. entra nas fotos
                {
                    //Entra Albuns
                    this.DoKeyDown(Key.Return);
                }
                else //Senão volta aos albuns
                {
                    //Sai Albuns
                    this.DoKeyDown(Key.Back);
                }
        }

        void kinect_SwipeEsquerda(object sender, EventArgs e)
        {
            if (_layouts[3] == _elementFlow.Layout) //Se está no carrosel
                this.DoKeyDown(Key.NumPad4);
            else
                this.DoKeyDown(Key.NumPad6);
        }
                
        void kinect_SwipeDireita(object sender, EventArgs e)
        {
            if (_layouts[3] == _elementFlow.Layout) //Se está no carrosel
                this.DoKeyDown(Key.NumPad6);
            else
                this.DoKeyDown(Key.NumPad4);
        }

        void kinect_MakeCirculo(object sender, EventArgs e)
        {
            //TODO: ZOOM na Imagem
        }

        void kinect_videoFrameKinect(object args)
        {
        }
        void kinect_posicoesMembros(object args)
        {
        }


        private void imgMedia_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Close();
        }
        #endregion

        #region Comandos de Voz
        void kinect_AudioZoom(object sender, EventArgs e)
        {
            this.DoKeyDown(Key.NumPad1);
        }

        void kinect_AudioReturn(object sender, EventArgs e)
        {
            SairAlbum();
        }

        void kinect_AudioEnter(object sender, EventArgs e)
        {
            EntrarAlbum();
        }

        void kinect_AudioPause(object sender, EventArgs e)
        {
            Pause();
        }

        void kinect_AudioBack(object sender, EventArgs e)
        {
            if (_layouts[3] == _elementFlow.Layout) //Se está no carrosel
                this.DoKeyDown(Key.NumPad6);
            else
                this.DoKeyDown(Key.NumPad4);
        }

        void kinect_AudioNext(object sender, EventArgs e)
        {
            if (_layouts[3] == _elementFlow.Layout) //Se está no carrosel
                this.DoKeyDown(Key.NumPad4);
            else
                this.DoKeyDown(Key.NumPad6);
        }
        #endregion


    }
}
